package com.htjc.integral.conversion.inner.util;

import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;

public class XflUtil
{
  public static String toXfs(Object object)
  {
    if (object == null) {
      return null;
    }
    if ((object instanceof List)) {
      return toXfs((List)object);
    }
    if ((object instanceof Map)) {
      return toXfs((Map)object);
    }

    StringWriter buffer = new StringWriter();
    XMLStreamWriter writer = createStartDocument(buffer);
    try {
      writer.writeStartElement("DBSET");
      writer.writeAttribute("RESULT", object.toString());
      writer.writeEndElement();
    }
    catch (XMLStreamException e)
    {
      e.printStackTrace();
    }
    return docAsXml(writer, buffer);
  }

  public static String toXfs(Map map)
  {
    StringWriter buffer = new StringWriter();
    XMLStreamWriter writer = createStartDocument(buffer);
    try {
      writer.writeStartElement("DBSET");
      addMapToRowElement(map, writer);
      writer.writeEndElement();
    }
    catch (XMLStreamException e)
    {
      e.printStackTrace();
    }

    return docAsXml(writer, buffer);
  }

  public static String toXfs(List list)
  {
    StringWriter buffer = new StringWriter();
    XMLStreamWriter writer = createStartDocument(buffer);

    if (list.size() > 0) {
      Object value = list.get(0);

      if ((value instanceof Map)) {
        addListToDbsetElement(list, writer);
      }
      else if ((value instanceof List))
        addListToDbsetElementOutside(list, writer);
    }
    else
    {
      addListToDbsetElement(list, writer);
    }
    return docAsXml(writer, buffer);
  }

  private static XMLStreamWriter createStartDocument(StringWriter buffer) {
    XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
    outputFactory.setProperty("javax.xml.stream.isRepairingNamespaces", new Boolean(true));

    XMLStreamWriter writer = null;
    try {
      writer = outputFactory.createXMLStreamWriter(buffer);
      writer.writeStartDocument("UTF-8", "1.0");
      writer.writeCharacters("\r\n");
    }
    catch (XMLStreamException e)
    {
      e.printStackTrace();
    }
    return writer;
  }

  private static String docAsXml(XMLStreamWriter writer, StringWriter buffer) {
    try {
      writer.writeEndDocument();
      writer.close();
      buffer.close();
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
    return buffer.toString();
  }

  private static void addListToDbsetElement(List srcList, XMLStreamWriter writer)
  {
    try {
      writer.writeStartElement("DBSET");
      writer.writeAttribute("RESULT", Integer.toString(srcList.size()));
      Iterator it = srcList.iterator();

      while (it.hasNext()) {
        Map map = (Map)it.next();
        addMapToRowElement(map, writer);
      }
      writer.writeEndElement();
    }
    catch (XMLStreamException e)
    {
      e.printStackTrace();
    }
  }

  private static void addMapToRowElement(Map map, XMLStreamWriter writer) {
    try {
      writer.writeStartElement("R");
      Iterator keyValuePairs = map.entrySet().iterator();

      for (int i = 0; i < map.size(); i++) {
        Map.Entry entry = (Map.Entry)keyValuePairs.next();
        String key = (String)entry.getKey();
        Object value = entry.getValue();
        writer.writeStartElement("C");
        writer.writeAttribute("N", key);
        if ((value == null) || ((value instanceof String))) {
          writer.writeCharacters(value == null ? "" : (String)value);
        }
        else if ((value instanceof List)) {
          addListToDbsetElement((List)value, writer);
        }
        else {
          writer.writeCharacters(value.toString());
        }
        writer.writeEndElement();
      }
      writer.writeEndElement();
    }
    catch (XMLStreamException e)
    {
      e.printStackTrace();
    }
  }

  private static void addListToDbsetElementOutside(List srcList, XMLStreamWriter writer)
  {
    try
    {
      writer.writeStartElement("DBSET");
      writer.writeAttribute("RESULT", Integer.toString(srcList.size()));
      Iterator it = srcList.iterator();

      while (it.hasNext()) {
        List list = (List)it.next();
        addListToRowElementOutside(list, writer);
      }
      writer.writeEndElement();
    }
    catch (XMLStreamException e)
    {
      e.printStackTrace();
    }
  }

  private static void addListToRowElementOutside(List list, XMLStreamWriter writer)
  {
    try
    {
      writer.writeStartElement("R");
      Iterator it = list.iterator();

      for (int i = 0; i < list.size(); i++) {
        Object value = list.get(i);
        if ((value == null) || ((value instanceof String))) {
          writer.writeCharacters(value == null ? "" : (String)value);
        }
        else if ((value instanceof List)) {
          addListToDbsetElementInside((List)value, writer);
        }
        else {
          writer.writeCharacters(value.toString());
        }
        writer.writeEndElement();
      }
      writer.writeEndElement();
    }
    catch (XMLStreamException e)
    {
      e.printStackTrace();
    }
  }

  private static void addListToDbsetElementInside(List srcList, XMLStreamWriter writer)
  {
    try
    {
      writer.writeStartElement("CDBSET");
      Iterator it = srcList.iterator();

      while (it.hasNext()) {
        Map map = (Map)it.next();
        addMapToRowElementInside(map, writer);
      }
    }
    catch (XMLStreamException e)
    {
      e.printStackTrace();
    }
  }

  private static void addMapToRowElementInside(Map map, XMLStreamWriter writer)
  {
    try {
      writer.writeStartElement("CR");
      Iterator keyValuePairs = map.entrySet().iterator();

      for (int i = 0; i < map.size(); i++) {
        Map.Entry entry = (Map.Entry)keyValuePairs.next();
        String key = (String)entry.getKey();
        Object value = entry.getValue();
        writer.writeStartElement("C");
        writer.writeAttribute("N", key);
        if ((value == null) || ((value instanceof String))) {
          writer.writeCharacters(value == null ? "" : (String)value);
        }
        else if ((value instanceof List)) {
          addListToDbsetElementInside((List)value, writer);
        }
        else {
          writer.writeCharacters(value.toString());
        }
        writer.writeEndElement();
      }
      writer.writeEndElement();
    }
    catch (XMLStreamException e)
    {
      e.printStackTrace();
    }
  }

  public static int getDbsetAttribute(String xmlStr)
  {
    XMLInputFactory inputFactory = XMLInputFactory.newInstance();
    String result = "0";
    XMLStreamReader reader = null;
    try {
      reader = inputFactory.createXMLStreamReader(new StringReader(xmlStr));

      while (reader.hasNext()) {
        if (dbsetStart(reader)) {
          result = reader.getAttributeValue(0);
          break;
        }
        reader.next();
      }
    }
    catch (XMLStreamException e) {
      e.printStackTrace();
      //throw new EPMRuntimeException("server.badXmlStr", new String[] { xmlStr });
    }
    finally
    {
      try {
        reader.close();
      }
      catch (XMLStreamException e) {
        e.printStackTrace();
      }
    }

    return Integer.parseInt(result);
  }

  public static List<Map> toList(String xmlStr) throws Exception
  {
    XMLInputFactory inputFactory = XMLInputFactory.newInstance();
    List list = new ArrayList();
    XMLStreamReader reader = null;
    try {
      reader = inputFactory.createXMLStreamReader(new StringReader(xmlStr));

      int cDbsetNumber = xmlStr.indexOf("CDBSET");
      if (cDbsetNumber > 0) {
        list = paresDbsetElementToListList(reader);
      }
      else {
        list = paresDbsetElementToList(reader);
      }
      reader.close();
    }
    catch (Exception e) {
      System.out.println("Can't resolve xml:" + xmlStr);
      e.printStackTrace();

      //throw new EPMRuntimeException("server.badXmlStr", new String[] { xmlStr });
    }
    finally
    {
      try {
        reader.close();
      }
      catch (XMLStreamException e) {
        e.printStackTrace();
      }
    }
    return list;
  }

  private static List paresDbsetElementToList(XMLStreamReader reader) throws Exception
  {
    List list = new ArrayList();
    try {
      while (reader.hasNext()) {
        if (rowStart(reader))
        {
          parseRowElementToMap(reader, list);
        }
        else if (dbsetEnd(reader)) {
            break;
          }
        reader.next();
      }
    }
    catch (Exception e)
    {
      throw e;
    }

    return list;
  }

  private static void parseRowElementToMap(XMLStreamReader reader, List list) throws Exception
  {
    Map map = new HashMap();
    try
    {
      while (reader.hasNext()) {
        int eventType = reader.getEventType();
        if (colStart(reader)) { String key = reader.getAttributeValue(0);
          Object value;
          try { String colText = reader.getElementText();
            value = (colText == null) || ("null".equalsIgnoreCase(colText)) ? "" : colText;
          }
          catch (Exception e)
          {
            reader.next();
            value = paresDbsetElementToList(reader);
          }
          map.put(key, value);
        }
        else if (rowEnd(reader)) {
          list.add(map);
          map = null;
          break;
        }
        reader.next();
      }

    }
    catch (XMLStreamException e)
    {
      throw e;
    }
  }

  private static List paresDbsetElementToListList(XMLStreamReader reader)
    throws Exception
  {
    List list = new ArrayList();
    try {
      while (reader.hasNext()) {
        if (rowStart(reader))
          parseRowElementToList(reader, list);
        else {
          if (dbsetEnd(reader))
            break;
        }
        reader.next();
      }
    }
    catch (Exception e)
    {
      throw e;
    }

    return list;
  }

  private static List parseRowElementToList(XMLStreamReader reader, List list)
    throws Exception
  {
    List rowList = new ArrayList();
    try {
      while (reader.hasNext()) {
        if (cDbsetStart(reader)) {
          paresCDbsetElementToList(reader, rowList);
        }
        else if (rowEnd(reader)) {
          list.add(rowList);
          rowList = null;
          break;
        }
        reader.next();
      }
    }
    catch (Exception e)
    {
      throw e;
    }

    return list;
  }

  private static List paresCDbsetElementToList(XMLStreamReader reader, List list)
    throws Exception
  {
    List cdbsetList = new ArrayList();
    try
    {
      while (reader.hasNext()) {
        if (cRowStart(reader)) {
          parseCRowElementToMap(reader, cdbsetList);
        }
        else if (cDbsetEnd(reader)) {
          list.add(cdbsetList);
          cdbsetList = null;
          break;
        }
        reader.next();
      }
    }
    catch (Exception e)
    {
      throw e;
    }

    return list;
  }

  private static void parseCRowElementToMap(XMLStreamReader reader, List list)
    throws Exception
  {
    Map map = new HashMap();
    try
    {
      while (reader.hasNext()) {
        int eventType = reader.getEventType();
        if (colStart(reader)) { String key = reader.getAttributeValue(0);
          Object value;
          try { String colText = reader.getElementText();
            value = (colText == null) || ("null".equalsIgnoreCase(colText)) ? "" : colText;
          }
          catch (Exception e)
          {
            reader.next();
            value = paresCDbsetElementToList(reader, list);
          }
          map.put(key, value);
        }
        else if (cRowEnd(reader)) {
          list.add(map);
          map = null;
          break;
        }
        reader.next();
      }

    }
    catch (XMLStreamException e)
    {
      throw e;
    }
  }

  private static boolean dbsetStart(XMLStreamReader reader) {
    return (reader.getEventType() == 1) && ("DBSET".equals(reader.getLocalName()));
  }

  private static boolean cDbsetStart(XMLStreamReader reader)
  {
    return (reader.getEventType() == 1) && ("CDBSET".equals(reader.getLocalName()));
  }

  private static boolean dbsetEnd(XMLStreamReader reader)
  {
    return (reader.getEventType() == 2) && ("DBSET".equals(reader.getLocalName()));
  }

  private static boolean cDbsetEnd(XMLStreamReader reader)
  {
    return (reader.getEventType() == 2) && ("CDBSET".equals(reader.getLocalName()));
  }

  private static boolean rowStart(XMLStreamReader reader)
  {
    return (reader.getEventType() == 1) && ("R".equals(reader.getLocalName()));
  }

  private static boolean cRowStart(XMLStreamReader reader)
  {
    return (reader.getEventType() == 1) && ("CR".equals(reader.getLocalName()));
  }

  private static boolean rowEnd(XMLStreamReader reader)
  {
    return (reader.getEventType() == 2) && ("R".equals(reader.getLocalName()));
  }

  private static boolean cRowEnd(XMLStreamReader reader)
  {
    return (reader.getEventType() == 2) && ("CR".equals(reader.getLocalName()));
  }

  private static boolean colStart(XMLStreamReader reader)
  {
    return (reader.getEventType() == 1) && ("C".equals(reader.getLocalName()));
  }

  private static boolean colEnd(XMLStreamReader reader)
  {
    return (reader.getEventType() == 2) && ("C".equals(reader.getLocalName()));
  }

  public static String toXfsZipString(Object object)
    throws Exception
  {
    return null;//ZipUtil.Zip(toXfs(object));
  }
  
  
  public static void main(String[] args) throws Exception {
	  XflUtil t =new XflUtil();
	  List<Map> list=t.toList("<DBSET><R><C N=\"rtnMsg\"></C><C N=\"id\">697D1517C860A1D8</C><C N=\"orgNo\">33101</C><C N=\"rtnCode\">1</C></R></DBSET>");
	  Map mReturn=null;
	  if(list.size()>0){
			mReturn=list.get(0);
		}
	  System.out.println(list.toString());
  }	
}
